package com.test.A30;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;

public class A30 {
    public static void main(String[] args) throws NoSuchMethodException {
    	
    	test2();
        /*
            学到了什么
                a. ExceptionHandlerExceptionResolver 能够重用参数解析器、返回值处理器，实现组件重用
                b. 能够支持嵌套异常
         */
    }
    
    /***
     *   @ResponseBody 测试 json
     * @throws NoSuchMethodException
     */
    public static void test1() throws NoSuchMethodException{
        ExceptionHandlerExceptionResolver resolver = new ExceptionHandlerExceptionResolver();
        resolver.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter()));//设置消息转换器   @ResponseBody
        resolver.afterPropertiesSet(); 
        //点进去以后 可以看到添加了默认的参数解析器和返回值解析器  getDefaultArgumentResolvers()    getDefaultReturnValueHandlers

        MockHttpServletRequest request = new MockHttpServletRequest();
        MockHttpServletResponse response = new MockHttpServletResponse();
        // 1.测试 json
          HandlerMethod handlerMethod = new HandlerMethod(new Controller1(), Controller1.class.getMethod("foo"));
         Exception e = new ArithmeticException("被零除");
         resolver.resolveException(request, response, handlerMethod, e);//请求  响应  控制器的方法  异常对象
         System.out.println(new String(response.getContentAsByteArray(), StandardCharsets.UTF_8));//得到异常的内容
    }
    
    
    /***
     * 返回值是ModelAndView的异常
     * @throws NoSuchMethodException
     */
    public static void test2() throws NoSuchMethodException{
        ExceptionHandlerExceptionResolver resolver = new ExceptionHandlerExceptionResolver();
        resolver.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter()));
        resolver.afterPropertiesSet();

        MockHttpServletRequest request = new MockHttpServletRequest();
        MockHttpServletResponse response = new MockHttpServletResponse();
        // 2.测试 mav
       HandlerMethod handlerMethod = new HandlerMethod(new Controller2(), Controller2.class.getMethod("foo"));
       Exception e = new ArithmeticException("被零除");
       ModelAndView mav = resolver.resolveException(request, response, handlerMethod, e);
       System.out.println(mav.getModel());//得到model的内容
       System.out.println(mav.getViewName());//得到视图的名称
    }
    
    
    /****
     * 测试异常处理方法参数解析  可以得到request对象
     * @throws NoSuchMethodException
     */
    public static void test3() throws NoSuchMethodException{
        ExceptionHandlerExceptionResolver resolver = new ExceptionHandlerExceptionResolver();
        resolver.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter()));
        resolver.afterPropertiesSet();

        MockHttpServletRequest request = new MockHttpServletRequest();
        MockHttpServletResponse response = new MockHttpServletResponse();
        // 4.测试异常处理方法参数解析
        HandlerMethod handlerMethod = new HandlerMethod(new Controller4(), Controller4.class.getMethod("foo"));
        Exception e = new Exception("e1");
        resolver.resolveException(request, response, handlerMethod, e);
        System.out.println(new String(response.getContentAsByteArray(), StandardCharsets.UTF_8));
    }
    
    
    
    /***
     * 测试嵌套异常 得到起因异常  可以得到对应的异常  本例可以得到e3的异常
     * @throws NoSuchMethodException
     */
    public static void test4() throws NoSuchMethodException{
        ExceptionHandlerExceptionResolver resolver = new ExceptionHandlerExceptionResolver();
        resolver.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter()));
        resolver.afterPropertiesSet();

        MockHttpServletRequest request = new MockHttpServletRequest();
        MockHttpServletResponse response = new MockHttpServletResponse();
        // 3.测试嵌套异常  得到内部异常  可以实现的原因是 会把所有的异常全部存到一个异常的数组中
       HandlerMethod handlerMethod = new HandlerMethod(new Controller3(), Controller3.class.getMethod("foo"));
       
       Exception e = new Exception("e1", new RuntimeException("e2", new IOException("e3")));
       
       
       resolver.resolveException(request, response, handlerMethod, e);
       System.out.println(new String(response.getContentAsByteArray(), StandardCharsets.UTF_8));
    }


    static class Controller1 {
        public void foo() {

        }
        @ExceptionHandler
        @ResponseBody
        public Map<String, Object> handle(ArithmeticException e) {
        	Map map=new HashMap();
        	map.put("error", e.getMessage());
            return map;
            //  return Map.of("error", e.getMessage());  //jdk9的用法
        }
    }

    static class Controller2 {
        public void foo() {

        }
        @ExceptionHandler
        public ModelAndView handle(ArithmeticException e) {
//            return new ModelAndView("test2", Map.of("error", e.getMessage()));
        	Map map=new HashMap();
        	map.put("error", e.getMessage());
            return new ModelAndView("test2", map);
        }
    }

    static class Controller3 {
        public void foo() {

        }
        @ExceptionHandler
        @ResponseBody
        public Map<String, Object> handle(IOException e3) {
         	Map map=new HashMap();
        	map.put("error", e3.getMessage());
        	return map;
            //return Map.of("error", e3.getMessage());
        }
    }

    static class Controller4 {
        public void foo() {}
        @ExceptionHandler
        @ResponseBody
        public Map<String, Object> handler(Exception e, HttpServletRequest request) {
            System.out.println(request);
        	Map map=new HashMap();
        	map.put("error", e.getMessage());
            return map;
        }
    }
}
